#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <limits.h>
#include "rnd.h"

#define ETYPE_PKT_ARRIVED    0
#define ETYPE_PKT_PROCESSED  1
#define ETYPE_PKT_DEQUEUED   2
#define ETYPE_PKT_ENQUEUED   3
#define ETYPE_PKT_DROPPED    4

#define BUFFER_PKT_SIZE 100000

#define MEASURE_INTERVAL 100

#define Kb(X) (uint64)X*1024
#define Mb(X) Kb((uint64)X*1024)
#define Gb(X) Mb((uint64)X*1024)

#define BUFFERSIZE Kb(512)
#define PROCSPEED  Gb(2)

#define TIME_PRECISION 1000000 /* i.e. 1 ns */

/**
   calculate processing time (ms)
   A: pkt size (B)
   B: proc speed (B/s)
*/
#define PROC_TIME(A,B)  (uint64)round((TIME_PRECISION * A) / (double)B)

typedef unsigned long long uint64;
typedef int etype;

typedef struct pkt_t
{
   uint64 arrival_time; /* when it got to the server */
   uint64 procinit_time; /* when its processing started */
   uint64 procfini_time; /* when its processing finished */
   int dropped; /* set to 1 if dropped when arrived */
   uint64 size;
} pkt_t;

typedef struct stat_t
{
   uint64 stat_clock; /* clock value when statistics began */
   uint64 pkt_proc_num;
   uint64 pkt_proc_bytes;
   uint64 pkt_arr_num;
   uint64 pkt_arr_bytes;
   uint64 pkt_dropped_num;
   double mean_delay;
   uint64 peek_num; /* how many times we peeked at queue size */
   uint64 queue_size; /* average queue size */
} stat_t;

typedef struct data_t
{
   uint64 timestamp;
   uint64 size;
} data_t;

typedef struct simu_t
{
   double arrival_rate;
   double size_rate;
   uint64 procspeed;
   uint64 buffer_size;
   uint64 steps;
   uint64 igsteps;
   uint64 curstep;
   uint64 clock;
   uint64 last_pkt_time; /* time when last pkt arrived */
   uint64 next_free; /* next free queue position */
   uint64 next_consume; /* next queue position to be read */
   uint64 queue_elno; /* queue element number{ */
   uint64 queue_size; /* size in bytes of occupied queue buffer */
   pkt_t* queue;
   data_t* data;
   uint64 data_index;
   uint64 data_size;
   stat_t stats;
} simu_t;
